package pkg

import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"runtime"
	"sync"
	"time"

	"github.com/shirou/gopsutil/v3/cpu"
)

const (
	refTime float64 = 210.431570589 // 时间基准 基于龙芯3A6000单核心计算时间(非超频)
	counter int64   = 100000000000  // 计算次数
)

type BeanchMarker struct {
	ModelName       string  `json:"modelName"` // 型号名称
	SingleCoreScore float64 `json:"singleCoreScore"`
	MultiCoreScore  float64 `json:"multiCoreScore"`
	Result          float64 `json:"result"`
}

func (b *BeanchMarker) String() string {
	r, err := json.Marshal(b)
	if err != nil {
		return "{}"
	}
	return string(r)
}

// x in {0, ...}
func Fn(x int64) float64 {
	y := 1.0 / float64(2*x+1)
	if x%2 != 0 {
		y = -y
	}
	return y
}

func Leibniz(x int64) float64 {
	var (
		Pi float64
		i  int64
	)

	for ; i < x; i++ {
		Pi += Fn(i)
	}
	return 4.0 * Pi
}

func LeibnizE(x int64) float64 {
	var wg sync.WaitGroup
	nc := runtime.NumCPU()

	piCh := make(chan float64, nc)
	wg.Add(nc)
	for i := 0; i < nc; i++ {
		var start, end int64
		start = int64(float64(x) * float64(i) / float64(nc))
		end = int64(float64(x) * float64(i+1) / float64(nc))
		go func(s, e int64) {
			var y float64
			for ; s < e; s++ {
				y += Fn(s)
			}
			piCh <- y
			wg.Done()
		}(start, end)
	}
	wg.Wait()
	close(piCh)

	var Pi float64
	for {
		pi, ok := <-piCh
		if ok {
			Pi += pi
		} else {
			break
		}
	}
	return 4.0 * Pi
}

func BeanchMarking() {
	bm := &BeanchMarker{}
	ci, err := cpu.Info()
	if err != nil {
		log.Fatal(err)
	}
	bm.ModelName = ci[0].ModelName

	start := time.Now()
	y := Leibniz(counter)
	end := time.Since(start)
	bm.SingleCoreScore = math.Round(refTime/end.Seconds()*10000.0) / 100.0

	if runtime.NumCPU() > 1 {
		start = time.Now()
		y = LeibnizE(counter)
		end = time.Since(start)
		bm.MultiCoreScore = math.Round(refTime/end.Seconds()*10000.0) / 100.0
	}
	bm.Result = y
	fmt.Println(bm.String())
}
